package uy.org.softtech.cssuite.tareas;

import static org.apache.commons.lang.ArrayUtils.isEmpty;
import static org.springframework.util.Assert.notNull;
import static uy.org.softtech.cssuite.helpers.HelperFechaHora.duracion;
import static uy.org.softtech.cssuite.helpers.HelperFechaHora.fechaActual;
import static uy.org.softtech.cssuite.helpers.HelperFechaHora.fechaLarga;
import static uy.org.softtech.cssuite.helpers.HelperTextos.URUGUAY;

import java.io.File;
import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.joda.time.Interval;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import uy.org.softtech.cssuite.core.TareaProgramada;
import uy.org.softtech.cssuite.entidad.sistema.Tarea;
import uy.org.softtech.cssuite.entidad.sistema.Tarea.Estado;
import uy.org.softtech.cssuite.excepciones.EntidadNoActualizadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoEncontradaException;
import uy.org.softtech.cssuite.repositorios.RepositorioTareas;

/**
 * Extensión de {@link TareaProgramada} encargada de eliminar los archivos considerados temporales en la aplicación.
 * 
 * @author fabian.lobo
 */
@Component(value = "tarea-archivos-temporales")
public class EliminarArchivosTemporales extends TareaProgramada {
	
	private Logger log = Logger.getLogger(getClass());
	
	@Value(value = "#{'${archivo.temporales.carpeta}'}")
	private String carpeta;
	
	@Value(value = "#{'${archivo.temporales.dias}'}")
	private int dias;
	
	@Resource(name = "repositorio-tareas")
	private RepositorioTareas repositorioTareas;
	
	/**
	 * Método para verificar que todos los parámetros han sido seteados correctamente.
	 * 
	 * @author fabian.lobo
	 */
	@PostConstruct
	public void inicializacion(){
		super.inicializacion();
		
		notNull(carpeta(), "La propiedad [carpeta] de [" + getClass().getName() + "] no ha sido establecida.");
		notNull(dias(), "La propiedad [dias] de [" + getClass().getName() + "] no ha sido establecida.");
		notNull(repositorioTareas(), "La propiedad [repositorioTareas] de [" + getClass().getName() + "] no ha sido establecida.");
		
		log.info("Tarea programada para eliminar los archivos considerados temporales ha sido inicializada.");
	}

	@Override
	@Scheduled(cron = TareaProgramada._1_AM) // Ejecuta cada día a la 1:00 AM 
	public void ejecutarTarea() {
				
		Date ahora = fechaActual();
		long comienzo = ahora.getTime();
		boolean exitoso = false;
		int contador = 0;
		
		log.info("Tarea iniciada el " + fechaLarga());
		log.info("Eliminando archivos generados después de " + dias() + " día(s) de la carpeta " + carpeta());
		
		//Actualizamos el estado en la base de datos
		try {
			Tarea tarea = repositorioTareas().buscarPorInstancia("tarea-archivos-temporales");
			tarea.setHoraComienzo(ahora);
			tarea.setEstado(Estado.ACTIVA);
			repositorioTareas().actualizar(tarea, SERVICIO);
		} catch (EntidadNoEncontradaException enee) {
			log.error(enee);
		} catch (EntidadNoActualizadaException enac) {
			log.error(enac);
		}
		
		try {
			File carpetaArchivosTemporales = new File(carpeta());
			if(carpetaArchivosTemporales.isDirectory()) {
				File[] archivos = carpetaArchivosTemporales.listFiles();
				if(!isEmpty(archivos)) {
					log.info("Archivos encontrados : " + archivos.length);
					for(File archivo : archivos){
						long fechaUltimaModificacion = archivo.lastModified();
						Interval intervalo = new Interval(fechaUltimaModificacion, comienzo);
						if(intervalo.toDuration().toStandardDays().getDays() >= dias()) {
							log.info("Archivo " + archivo.getName() + " ha sido eliminado.");
							archivo.delete();
							contador++;
						}
					}
					log.info("Archivos eliminados : " + contador);
				} else {
					log.info("Archivos encontrados : 0");
				}
				exitoso = true;
			} else {
				throw new RuntimeException("La ruta proporcionada [" + carpeta() + "] no es una carpeta válida.");
			}
		} catch (Throwable t) {
			log.error(t);
		} finally {
									
			ahora = fechaActual();
			long fin = ahora.getTime();
			Interval intervalo = new Interval(comienzo, fin);
			
			//Actualizamos la tarea en la base de datos
			try {
				Tarea tarea = repositorioTareas().buscarPorInstancia("tarea-archivos-temporales");
				tarea.setHoraFin(ahora);
				tarea.setEstado(Estado.TERMINADA);
				tarea.setEjecuciones(tarea.getEjecuciones() + 1);
				
				if(exitoso) {
					tarea.setExitosas(tarea.getExitosas() + 1);
					tarea.setHoraUltimaExitosa(intervalo.getEnd().toDate());
				} else {
					tarea.setFallidas(tarea.getFallidas() + 1);
					tarea.setHoraUltimaFallida(intervalo.getStart().toDate());
				}
				
				repositorioTareas().actualizar(tarea, SERVICIO);
			} catch (EntidadNoEncontradaException enee) {
				log.error(enee);
			} catch (EntidadNoActualizadaException enac) {
				log.error(enac);
			}
			
			log.info("Tarea finalizada el " + fechaLarga());
			log.info("Duración: " + duracion(comienzo, fin, URUGUAY));
		}
		
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("EliminarArchivosTemporales [");
		builder.append(String.format("agenda='%s'", TareaProgramada._1_AM) + ", ");
		builder.append("carpeta=" + carpeta() + ", ");
		builder.append("dias="  + dias());
		builder.append("]");
		return builder.toString();
	}

	/*
	 *  GETTERS
	 */
	public String carpeta() {
		return carpeta;
	}
	public int dias() {
		return dias;
	}
	private RepositorioTareas repositorioTareas() {
		return repositorioTareas;
	}
}
